﻿using System;
using System.Collections.Generic;
using CollegeSim.Domain.DTO;
using CollegeSim.Domain.Interfaces.Repositories;
using CollegeSim.Domain.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace CollegeSim.Domain.Test.Services
{
    // Author: Ryan Redburn
    // Project: CollegeSim
    // Date: 5/13/2014

    #region [ Updates ]

    // Author: Ryan Redburn
    // Date: 5/18/2014
    // Revisions: Fixed logic errors present in some tests. Added missing tests for GetAll() valid calls and GetByID() valid calls.

    #endregion

    [TestClass]
    public class CourseServiceTest
    {
        #region [ GetAll() ]

        [TestMethod]
        public void CourseServiceGetAll_InvalidDataReceived_InvalidOperationException()
        {
            // Arrange
            var assert = false;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "",
                Number = "",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            List<CourseDTO> courses = null;
            var courseReturn = new List<CourseDTO> { course } as IEnumerable<CourseDTO>;
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindAll()).Returns(courseReturn);

            try
            {
                // Act
                courses = courseService.GetAll();
            }
            catch (InvalidOperationException)
            {
                assert = true;
            }
            finally
            {
                // Assert
                Assert.IsNull(courses);
                Assert.IsTrue(assert);
            }
        }

        [TestMethod]
        public void CourseServiceGetAll_ValidCall_ExpectedReturn()
        {
            // Arrange
            var assert = true;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            List<CourseDTO> courses = null;
            var courseReturn = new List<CourseDTO> { course } as IEnumerable<CourseDTO>;
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindAll()).Returns(courseReturn);

            try
            {
                // Act
                courses = courseService.GetAll();
            }
            catch (Exception)
            {
                assert = false;
            }
            finally
            {
                // Assert
                Assert.IsNotNull(courses);
                Assert.IsTrue(assert);
            }
        }

        #endregion

        #region [ GetByID() ]

        [TestMethod]
        public void CourseServiceGetByID_IDBelowRange_ArgumentOutOfRangeException()
        {
            // Arrange
            var assert = false;
            CourseDTO course = null;
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            try
            {
                // Act
                course = courseService.GetByID(-1);
            }
            catch (ArgumentOutOfRangeException)
            {
                assert = true;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
                Assert.IsNull(course);
            }
        }

        [TestMethod]
        public void CourseServiceGetByID_InvalidDataReceived_InvalidOperationException()
        {
            // Arrange
            var assert = false;
            CourseDTO course = null;
            var invalidCourse = new CourseDTO
            {
                CourseID = 1,
                Subject = "",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindByID(1)).Returns(invalidCourse);

            try
            {
                // Act
                course = courseService.GetByID(1);
            }
            catch (InvalidOperationException)
            {
                assert = true;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
                Assert.IsNull(course);
            }
        }

        [TestMethod]
        public void CourseServiceGetByID_ValidCall_ExpectedReturn()
        {
            // Arrange
            var assert = true;
            CourseDTO course = null;
            var courseReturn = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindByID(1)).Returns(courseReturn);

            try
            {
                // Act
                course = courseService.GetByID(1);
            }
            catch (Exception)
            {
                assert = false;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
                Assert.IsNotNull(course);
            }
        }

        #endregion

        #region [ Commit() ]

        [TestMethod]
        public void CourseServiceCommit_ValidCall_ExpectedReturn()
        {
            // Arrange
            var assert = true;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();

            try
            {
                // Act
                courseService.Commit(course);
            }
            catch (Exception)
            {
                assert = false;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
            }
        }

        #endregion

        #region [ Update() ]

        [TestMethod]
        public void CourseServiceUpdate_NonExistentID_InvalidOperationException()
        {
            // Arrange
            var assert = false;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            courseRepo.Setup(cr => cr.FindByID(1)).Returns((CourseDTO)null);

            try
            {
                // Act
                courseService.Update(course.CourseID, course);
            }
            catch (InvalidOperationException)
            {
                assert = true;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
            }
        }

        [TestMethod]
        public void CourseServiceUpdate_ValidCall_ExpectedReturn()
        {
            // Arrange
            var assert = true;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindByID(1)).Returns(course);

            try
            {
                // Act
                courseService.Update(course.CourseID, course);
            }
            catch (InvalidOperationException)
            {
                assert = false;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
            }
        }

        #endregion

        #region [ Delete() ]

        [TestMethod]
        public void CourseServiceDelete_NonExistentID_InvalidOperationException()
        {
            // Arrange
            var assert = false;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            try
            {
                // Act
                courseService.Delete(course);
            }
            catch (InvalidOperationException)
            {
                assert = true;
            }
            finally
            {
                Assert.IsTrue(assert);
            }
        }

        [TestMethod]
        public void CourseServiceDelete_ValidCall_ExpectedReturn()
        {
            // Arrange
            var assert = true;
            var course = new CourseDTO
            {
                CourseID = 1,
                Subject = "CIT",
                Number = "190",
                Title = "JavaScript Programming",
                CreditHours = 2,
                ContactHours = 2,
                Online = false,
                Hybrid = true
            };
            var courseRepo = new Mock<ICourseRepository>();
            var courseService = new CourseService(courseRepo.Object);

            DomainMapConfig.Initialize();
            courseRepo.Setup(cr => cr.FindByID(1)).Returns(course);

            try
            {
                // Act
                courseService.Delete(course);
            }
            catch (InvalidOperationException)
            {
                assert = false;
            }
            finally
            {
                // Assert
                Assert.IsTrue(assert);
            }
        }

        #endregion
    }
}
